package com.hd123.rumba.runtime;

import java.util.Date;
import java.util.Vector;

import com.hd123.rumba.runtime.FormatSettings;

/**
 * 用来管理由用户界面触发的长时间的处理, 是带存储的控制类. <br>
 * 这些处理被保存在processes中. 处理完成后, 不会从processes中自动删除.<br>
 * Key: userId+processId 通常使用process的类名作为processId<br>
 * 典型的用法是:<br>
 * <li>触发者:<br>
 * 启动: runOnce(user.getUuid(), WorkerClass.getName(), worker);<br>
 * 轮询: procInfo = getProcessInfo(user.getUuid(), WorkerClass.getName());<br>
 * 取得procInfo.state, procInfo.percentage, ...<br>
 * 得到完成状态后, removeProcessInfo<br>
 * <li>执行者:<br>
 * updateProcessInfo();<br>
 * 
 * @author caili
 */
public class RunOnce {
  /**
   * 存储运行的process信息
   */
  private static Vector<RunOnceInfo> processes = new Vector();

  /**
   * 如果指定的userId+processId已经存在, 返回其ProcessInfo; 否则启动执行线程, 并返回其ProcessInfo.
   * 
   * @param process
   * @return
   */
  public static RunOnceInfo run(String userId, String processId, final Runnable process) {
    synchronized (processes) {
      RunOnceInfo pif = findProcessInfo(userId, processId);
      if (pif != null)
        return pif;
      pif = new RunOnceInfo();
      processes.add(pif);
      pif.setUserId(userId);
      pif.setProcessId(processId);
      pif.setStartTime(new Date());
      pif.setLastUpdated(null);
      pif.setEndTime(null);
      pif.setPercentage(0);
      pif.setState(RunOnceInfo.STATE_RUNNING);
      pif.thread = new Thread() {
        public void run() {
          process.run();
        }
      };
      pif.thread.setName(processId);
      pif.thread.start();
      return pif;
    }
  }

  /**
   * @param userId
   *          required
   * @param processId
   *          required
   * @param endTime
   *          null means keep the old value
   * @param percentage
   * @param state
   * @param info
   * @return
   */
  public static boolean updateProcessInfo(String userId, String processId, Date endTime,
      int percentage, int state, String info) {
    synchronized (processes) {
      RunOnceInfo pif = findProcessInfo(userId, processId);
      if (pif == null)
        return false;
      pif.setEndTime(endTime);
      pif.setPercentage(percentage);
      if (info != null)
        pif.getInfo().append(FormatSettings.SDFyMdHms.format(new Date()) + ": " + info);
      pif.setState(state);
      pif.setLastUpdated(new Date());
      return true;
    }
  }
  
  /**
   * 由worker调用
   * @param userId
   * @param processId
   * @return
   */
  public static boolean setResult(String userId, String processId, Object result) {
    RunOnceInfo pif = findProcessInfo(userId, processId);
    if (pif == null)
      return false;
    pif.setResult(result);
    return true;
  }

  /**
   * @param userId
   * @param processId
   */
  public static RunOnceInfo getProcessInfo(String userId, String processId) {
    synchronized (processes) {
      RunOnceInfo pif = findProcessInfo(userId, processId);
      // 如果工作线程没有正确设置state就结束了, 这里把它设置成ERROR
      if (pif != null && pif.getThread().getThreadGroup() == null) {
        updateProcessInfo(userId, processId, null, 100, RunOnceInfo.STATE_ERROR, "执行完成.");
      }
      return pif;
    }
  }

  /**
   * @param process
   */
  public static void removeProcessInfo(String userId, String processId) {
    synchronized (processes) {
      int i = 0;
      while (i < processes.size()) {
        if (processes.get(i).userId.equals(userId) && processes.get(i).processId.equals(processId))
          break;
        ++i;
      }
      if (i < processes.size())
        processes.remove(i);
    }
  }

  /**
   * 根据userId+processId找到并返回processes中的那个对象
   * 
   * @param userId
   * @param processId
   * @return
   */
  private static RunOnceInfo findProcessInfo(String userId, String processId) {
    int i = 0;
    while (i < processes.size()) {
      if (processes.get(i).userId.equals(userId) && processes.get(i).processId.equals(processId))
        return processes.get(i);
      ++i;
    }
    return null;
  }

}
